package com.general;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.*;
import java.util.concurrent.Callable;

/**
 * @author gjy
 * @version 1.0
 * @since 2025-10-09 14:56:12
 */
public class SQLTask implements Callable<ResultSet> {
    private static final Logger log = LoggerFactory.getLogger(SQLTask.class);

    private final String url;
    private final String username;
    private final String password;
    private final Integer timeout;
    private final String sql;

    public SQLTask(String url, String username, String password, Integer timeout, String sql) {
        this.url = url;
        this.username = username;
        this.password = password;
        this.timeout = timeout;
        this.sql = sql;
    }

    private volatile Statement currentStatement;
    private volatile boolean isCancelled = false;

    @Override
    public ResultSet call() throws Exception {
        Connection connection = null;
        ResultSet resultSet = null;

        try {
            connection = DriverManager.getConnection(url, username, password);

            currentStatement = connection.createStatement();
            currentStatement.setQueryTimeout(timeout);

            // 检查是否已被取消
            if (isCancelled) {
                throw new InterruptedException("任务已被取消");
            }

            resultSet = currentStatement.executeQuery(sql);

            // 检查中断
            if (Thread.currentThread().isInterrupted() || isCancelled) {
                throw new InterruptedException("SQL执行过程中被中断");
            }

            return resultSet;

        } catch (SQLException e) {
            if (isCancelled || Thread.currentThread().isInterrupted()) {
                log.error("SQL执行被取消或中断: {}", e.getMessage());
                throw new InterruptedException("SQL执行被取消");
            }

            if (e.getMessage().toLowerCase().contains("timeout") || e.getMessage().toLowerCase().contains("cancel") || e.getErrorCode() == 1317) {
                log.error("SQL执行超时或被取消: {}", e.getMessage());
                throw new RuntimeException("SQL执行超时", e);
            }

            log.error("SQL执行异常: {}", e.getMessage());
            throw e;
        } finally {
            closeResources(resultSet, currentStatement, connection);
        }
    }

    public void cancelSQL() {
        isCancelled = true;
        if (currentStatement != null) {
            try {
                log.info("正在取消SQL执行...");
                currentStatement.cancel();
                log.info("SQL执行已取消");
            } catch (SQLException e) {
                log.error("取消SQL执行时出错: {}", e.getMessage());
            }
        }
    }

    // 关闭数据库资源的工具方法
    private static void closeResources(ResultSet resultSet, Statement statement, Connection connection) {
        try {
            if (resultSet != null) resultSet.close();
        } catch (SQLException e) {
            log.error("关闭ResultSet时出错: {}", e.getMessage());
        }

        try {
            if (statement != null) statement.close();
        } catch (SQLException e) {
            log.error("关闭Statement时出错: {}", e.getMessage());
        }

        try {
            if (connection != null) connection.close();
        } catch (SQLException e) {
            log.error("关闭Connection时出错: {}", e.getMessage());
        }
    }

}
